%     FASTENER DOCTOR - программа для лечения и конвертации крепежа
%     Copyright (C) 2018  Михаил Козлов
%     Сайт проекта: <http://www.fastenerdoctor.ru/>
%     Адрес электронной почты для связи с разработчиком:
%     <doctor.fastener@gmail.com>
% 
%     Эта программа является свободным программным обеспечением: Вы можете
%     распространять ее и/или изменять, соблюдая условия Универсальной общественной
%     лицензии GNU, опубликованной Фондом свободного программного обеспечения,
%     либо редакции 3, либо (на Ваше усмотрение) любой редакции, выпущенной позже.
% 
%     Эта программа распространяется в надежде на то, что она окажется полезной,
%     но БЕЗ КАКИХ-ЛИБО ГАРАНТИЙ, включая даже подразумеваемую гарантию ТОВАРНОЙ ПРИГОДНОСТИ,
%     либо ПРИГОДНОСТИ ДЛЯ ОПРЕДЕЛЕННЫХ ЦЕЛЕЙ. Ознакомьтесь с Универсальной общественной
%     лицензией GNU для получения более подробной информации.
% 
%     Вы должны были получить копию Универсальной общественной лицензии GNU
%     вместе с этой программой. Если Вы ее не получили, то перейдите по адресу:
%     <http://www.gnu.org/licenses/>.
% 
%     This program is free software: you can redistribute it and/or modify
%     it under the terms of the GNU General Public License as published by
%     the Free Software Foundation, either version 3 of the License, or
%     (at your option) any later version.
% 
%     This program is distributed in the hope that it will be useful,
%     but WITHOUT ANY WARRANTY; without even the implied warranty of
%     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
%     GNU General Public License for more details.
% 
%     You should have received a copy of the GNU General Public License
%     along with this program.  If not, see <https://www.gnu.org/licenses/>.

function [JT_type, Connected_elements, Bar_Spider_Elements, Bar_Spider_Connected_Nodes, Err_Message] = Recognize_Joint_Topology(Joint_node, Element_list, MPC_list)

global DB_ELEMENTS;
global DB_MPC;

global AT_ELEMENTS;
global AT_MPC;

global Load_RBE3_minimum_indep_nodes;

JT_type = [];
Connected_elements = [];
Bar_Spider_Elements = [];
Bar_Spider_Connected_Nodes = [];
Err_Message = [];

% Исключение RBE3, ассоциированных с Joint_node и служащих для раздачи нагрузки в модели

if ((~isempty(MPC_list)) && (~isempty(Element_list)))
    
    Excluded_RBE3 = zeros(10,1);
    counter = 0;
    
    for i=1:numel(MPC_list)
        if (strcmp(DB_MPC{AT_MPC(MPC_list(i))}.type, 'RBE3'))
            if (DB_MPC{AT_MPC(MPC_list(i))}.dep_grid ~= Joint_node)
                if (size(DB_MPC{AT_MPC(MPC_list(i))}.ind_data,1) >= Load_RBE3_minimum_indep_nodes)
                    counter = counter + 1;
                    Excluded_RBE3(counter) = MPC_list(i);
                end
            end
        end
    end
    
    if (counter == 0)
        Excluded_RBE3 = [];
    else
        Excluded_RBE3 = Excluded_RBE3(1:counter);
    end

    if (~isempty(Excluded_RBE3))
        MPC_list = setdiff(MPC_list, Excluded_RBE3);
        if (isempty(MPC_list))
            MPC_list = [];
        end
    end
    
end

% --- Крепление болта только к MPC ---

if ((~isempty(MPC_list)) && isempty(Element_list))
    
    % Должен быть один MPC
    if (size(MPC_list,1) ~= 1)
        Err_Message = [sprintf('Сетка, окружающая болт на данном ярусе, потенциально имеет тип RBE2_2D_HOLE, RBE2_3D_HOLE, либо PLATE_RBE2_SEQUENTIAL\n') ...
                       sprintf('(см. описание в руководстве пользователя).\n') ...
                       sprintf('В этом случае болт должен соединяться лишь с одним MPC.\n') ...
                       sprintf('В данной ситуации болт соединен с несколькими MPC.')];
        return;
    end
    
    % Допускается тип MPC RBE2 или RBE3
    if (~(strcmp(DB_MPC{AT_MPC(MPC_list(1))}.type, 'RBE2') || strcmp(DB_MPC{AT_MPC(MPC_list(1))}.type, 'RBE3')))
        Err_Message = [sprintf('Сетка, окружающая болт на данном ярусе, потенциально имеет тип RBE2_2D_HOLE, RBE2_3D_HOLE, либо PLATE_RBE2_SEQUENTIAL\n') ...
                       sprintf('(см. описание в руководстве пользователя).\n') ...
                       sprintf('В этом случае MPC, к которому крепится болт, должен быть типа RBE2.\n') ...
                       sprintf('В данной ситуации MPC имеет отличный от RBE2 тип.')];
        return;
    end
    
    % Ветвление по типу MPC
    switch DB_MPC{AT_MPC(MPC_list(1))}.type
        
        case 'RBE2'
            
            % Узел Joint_node должен быть независимым
            if (DB_MPC{AT_MPC(MPC_list(1))}.ind_grid ~= Joint_node)
                Err_Message = [sprintf('Сетка, окружающая болт на данном ярусе, потенциально имеет тип RBE2_2D_HOLE, RBE2_3D_HOLE, либо PLATE_RBE2_SEQUENTIAL\n') ...
                               sprintf('(см. описание в руководстве пользователя).\n') ...
                               sprintf('В этом случае узел MPC, к которому крепится болт, должен быть независимым.\n') ...
                               sprintf('В данной ситуации болт крепится к зависимому узлу MPC.')];
                return;
            end
            
            % Список присоединенных MPC
            Connected_MPCs = Get_MPCs_From_Nodes(DB_MPC{AT_MPC(MPC_list(1))}.dep_grid, MPC_list(1));
            
            % Исключение RBE3, служащих для раздачи нагрузки в модели
            if (~isempty(Connected_MPCs))
            
                Excluded_RBE3 = zeros(10,1);
                counter = 0;

                for i=1:numel(Connected_MPCs)
                    if (strcmp(DB_MPC{AT_MPC(Connected_MPCs(i))}.type, 'RBE3'))
                        if (~ismember(DB_MPC{AT_MPC(Connected_MPCs(i))}.dep_grid, DB_MPC{AT_MPC(MPC_list(1))}.dep_grid))
                            if (size(DB_MPC{AT_MPC(Connected_MPCs(i))}.ind_data,1) >= Load_RBE3_minimum_indep_nodes)
                                counter = counter + 1;
                                Excluded_RBE3(counter) = Connected_MPCs(i);
                            end
                        end
                    end
                end
                
                if (counter == 0)
                    Excluded_RBE3 = [];
                else
                    Excluded_RBE3 = Excluded_RBE3(1:counter);
                end
                
                if (~isempty(Excluded_RBE3))
                    Connected_MPCs = setdiff(Connected_MPCs, Excluded_RBE3);
                    if (isempty(Connected_MPCs))
                        Connected_MPCs = [];
                    end
                end
            
            end
            
            % Список присоединенных MPC должен быть пустым
            if (~isempty(Connected_MPCs))
                Err_Message = [sprintf('Сетка, окружающая болт на данном ярусе, потенциально имеет тип RBE2_2D_HOLE, RBE2_3D_HOLE, либо PLATE_RBE2_SEQUENTIAL\n') ...
                               sprintf('(см. описание в руководстве пользователя).\n') ...
                               sprintf('В этом случае с зависимыми узлами RBE2, к которому крепится болт, не должно быть ассоциировано никаких иных MPC.\n') ...
                               sprintf('(Исключение могут составлять только RBE3, служащие для раздачи нагрузки; у таких RBE3 должно быть не менее %i независимых узлов).\n', Load_RBE3_minimum_indep_nodes) ...
                               sprintf('В данной ситуации существует посторонний MPC, ассоциированный с зависимыми узлами RBE2.')];
                return;
            end
            
            % Список присоединенных элементов должен быть не пустым
            Connected_ELMs = Get_Elements_From_Nodes(DB_MPC{AT_MPC(MPC_list(1))}.dep_grid, []);
            
            if (isempty(Connected_ELMs))
                Err_Message = [sprintf('Сетка, окружающая болт на данном ярусе, потенциально имеет тип RBE2_2D_HOLE, RBE2_3D_HOLE, либо PLATE_RBE2_SEQUENTIAL\n') ...
                               sprintf('(см. описание в руководстве пользователя).\n') ...
                               sprintf('В этом случае с зависимыми узлами RBE2, к которому крепится болт, должны быть ассоциированы конечные элементы.\n') ...
                               sprintf('В данной ситуации с зависимыми узлами RBE2 не ассоциировано ни одного элемента.')];
                return;
            end
            
            % У каждого зависимого узла MPC должны быть присоединенные элементы
            for i=1:size(DB_MPC{AT_MPC(MPC_list(1))}.dep_grid,1)
                Single_node_elements = Get_Elements_From_Nodes(DB_MPC{AT_MPC(MPC_list(1))}.dep_grid(i), []);
                if (isempty(Single_node_elements))
                    Err_Message = [sprintf('Сетка, окружающая болт на данном ярусе, потенциально имеет тип RBE2_2D_HOLE, RBE2_3D_HOLE, либо PLATE_RBE2_SEQUENTIAL\n') ...
                                   sprintf('(см. описание в руководстве пользователя).\n') ...
                                   sprintf('В этом случае с каждым зависимым узлом RBE2, к которому крепится болт, должен быть ассоциирован хотя бы один конечный элемент.\n') ...
                                   sprintf('В данной ситуации существует зависимый узел RBE2, с которым не ассоциировано ни одного элемента.')];
                    return;
                end
            end
            
            % Первый присоединенный элемент должен быть shell, либо solid
            switch DB_ELEMENTS{AT_ELEMENTS(Connected_ELMs(1))}.type
                case 'Tet'
                    % Допустимый тип элемента
                    Elm_family = 3;
                case 'Wedge'
                    % Допустимый тип элемента
                    Elm_family = 3;
                case 'Hex'
                    % Допустимый тип элемента
                    Elm_family = 3;
                case 'Quad'
                    % Допустимый тип элемента
                    Elm_family = 2;
                case 'Tria'
                    % Допустимый тип элемента
                    Elm_family = 2;
                otherwise
                    Err_Message = [sprintf('Сетка, окружающая болт на данном ярусе, потенциально имеет тип RBE2_2D_HOLE, RBE2_3D_HOLE, либо PLATE_RBE2_SEQUENTIAL\n') ...
                                   sprintf('(см. описание в руководстве пользователя).\n') ...
                                   sprintf('В этом случае с зависимыми узлами RBE2, к которому крепится болт, должны быть ассоциированы оболочечные, либо твердотельные конечные элементы.\n') ...
                                   sprintf('В данной ситуации существует зависимый узел RBE2, с которым ассоциированы элементы другого типа.')];
                    return;
            end
            
            % Ветвление по семейству элементов
            switch Elm_family
                
                case 2
                    
                    % Все присоединенные элементы должны быть типа shell
                    for i=1:size(Connected_ELMs,1)
                        if (~(strcmp(DB_ELEMENTS{AT_ELEMENTS(Connected_ELMs(i))}.type, 'Quad') ...
                           || strcmp(DB_ELEMENTS{AT_ELEMENTS(Connected_ELMs(i))}.type, 'Tria')))
                            Err_Message = [sprintf('Сетка, окружающая болт на данном ярусе, потенциально имеет тип RBE2_2D_HOLE, либо PLATE_RBE2_SEQUENTIAL\n') ...
                                           sprintf('(см. описание в руководстве пользователя).\n') ...
                                           sprintf('В этом случае все конечные элементы, ассоциированные с зависимыми узлами RBE2, к которому крепится болт, должны быть оболочечными.\n') ...
                                           sprintf('В данной ситуации среди элементов, ассоциированных с зависимыми узлами RBE2, существуют элементы другого типа.')];
                            return;
                        end
                    end
                    
                    % Должно быть не меньше 3 элементов
                    if (size(Connected_ELMs,1) < 3)
                        Err_Message = [sprintf('Сетка, окружающая болт на данном ярусе, потенциально имеет тип RBE2_2D_HOLE, либо PLATE_RBE2_SEQUENTIAL\n') ...
                                       sprintf('(см. описание в руководстве пользователя).\n') ...
                                       sprintf('В этом случае число конечных элементов, ассоциированных с зависимыми узлами RBE2, к которому крепится болт, должно быть не менее 3.\n') ...
                                       sprintf('В данной ситуации число элементов, ассоциированных с зависимыми узлами RBE2, меньше 3.')];
                        return;
                    end
                    
                    % Все присоединенные элементы должны быть одного порядка
                    switch DB_ELEMENTS{AT_ELEMENTS(Connected_ELMs(1))}.type
                        case 'Quad'
                            switch DB_ELEMENTS{AT_ELEMENTS(Connected_ELMs(1))}.N_nodes
                                case 4
                                    Element_order = 1;
                                case 8
                                    Element_order = 2;
                            end
                        case 'Tria'
                            switch DB_ELEMENTS{AT_ELEMENTS(Connected_ELMs(1))}.N_nodes
                                case 3
                                    Element_order = 1;
                                case 6
                                    Element_order = 2;
                            end
                    end
                    
                    for i=1:size(Connected_ELMs,1)
                        switch DB_ELEMENTS{AT_ELEMENTS(Connected_ELMs(i))}.type
                            case 'Quad'
                                switch Element_order
                                    case 1
                                        if (DB_ELEMENTS{AT_ELEMENTS(Connected_ELMs(i))}.N_nodes ~= 4)
                                            Err_Message = [sprintf('Сетка, окружающая болт на данном ярусе, потенциально имеет тип RBE2_2D_HOLE, либо PLATE_RBE2_SEQUENTIAL\n') ...
                                                           sprintf('(см. описание в руководстве пользователя).\n') ...
                                                           sprintf('В этом случае все конечные элементы, ассоциированные с зависимыми узлами RBE2, к которому крепится болт, должны быть одного порядка.\n') ...
                                                           sprintf('В данной ситуации конечные элементы, ассоциированные с зависимыми узлами RBE2, различаются по порядку.')];
                                            return;
                                        end
                                    case 2
                                        if (DB_ELEMENTS{AT_ELEMENTS(Connected_ELMs(i))}.N_nodes ~= 8)
                                            Err_Message = [sprintf('Сетка, окружающая болт на данном ярусе, потенциально имеет тип RBE2_2D_HOLE, либо PLATE_RBE2_SEQUENTIAL\n') ...
                                                           sprintf('(см. описание в руководстве пользователя).\n') ...
                                                           sprintf('В этом случае все конечные элементы, ассоциированные с зависимыми узлами RBE2, к которому крепится болт, должны быть одного порядка.\n') ...
                                                           sprintf('В данной ситуации конечные элементы, ассоциированные с зависимыми узлами RBE2, различаются по порядку.')];
                                            return;
                                        end
                                end
                            case 'Tria'
                                switch Element_order
                                    case 1
                                        if (DB_ELEMENTS{AT_ELEMENTS(Connected_ELMs(i))}.N_nodes ~= 3)
                                            Err_Message = [sprintf('Сетка, окружающая болт на данном ярусе, потенциально имеет тип RBE2_2D_HOLE, либо PLATE_RBE2_SEQUENTIAL\n') ...
                                                           sprintf('(см. описание в руководстве пользователя).\n') ...
                                                           sprintf('В этом случае все конечные элементы, ассоциированные с зависимыми узлами RBE2, к которому крепится болт, должны быть одного порядка.\n') ...
                                                           sprintf('В данной ситуации конечные элементы, ассоциированные с зависимыми узлами RBE2, различаются по порядку.')];
                                            return;
                                        end
                                    case 2
                                        if (DB_ELEMENTS{AT_ELEMENTS(Connected_ELMs(i))}.N_nodes ~= 6)
                                            Err_Message = [sprintf('Сетка, окружающая болт на данном ярусе, потенциально имеет тип RBE2_2D_HOLE, либо PLATE_RBE2_SEQUENTIAL\n') ...
                                                           sprintf('(см. описание в руководстве пользователя).\n') ...
                                                           sprintf('В этом случае все конечные элементы, ассоциированные с зависимыми узлами RBE2, к которому крепится болт, должны быть одного порядка.\n') ...
                                                           sprintf('В данной ситуации конечные элементы, ассоциированные с зависимыми узлами RBE2, различаются по порядку.')];
                                            return;
                                        end
                                end
                        end
                    end
                    
                    % Должно быть не менее 2 зависимых узлов у RBE2
                    if (size(DB_MPC{AT_MPC(MPC_list(1))}.dep_grid,1) < 2)
                        Err_Message = [sprintf('Сетка, окружающая болт на данном ярусе, потенциально имеет тип RBE2_2D_HOLE, либо PLATE_RBE2_SEQUENTIAL\n') ...
                                       sprintf('(см. описание в руководстве пользователя).\n') ...
                                       sprintf('В этом случае у RBE2, к которому крепится болт, должно быть не менее 2 зависимых узлов.\n') ...
                                       sprintf('В данной ситуации число зависимых узлов RBE2, к которому крепится болт, меньше 2.')];
                        return;
                    end
                    
                    % Тест на 2d отверстие
                    if (Hole_2D_Test(Joint_node, DB_MPC{AT_MPC(MPC_list(1))}.dep_grid, []))
                        
                        % Должно быть не менее 3 зависимых узлов у RBE2
                        if (size(DB_MPC{AT_MPC(MPC_list(1))}.dep_grid,1) < 3)
                            Err_Message = [sprintf('Сетка, окружающая болт на данном ярусе, потенциально имеет тип RBE2_2D_HOLE\n') ...
                                           sprintf('(см. описание в руководстве пользователя).\n') ...
                                           sprintf('В этом случае у RBE2, к которому крепится болт, должно быть не менее 3 зависимых узлов.\n') ...
                                           sprintf('В данной ситуации число зависимых узлов RBE2, к которому крепится болт, меньше 3.')];
                            return;
                        end
                        
                        % Назначение типа присоединенной топологии
                        JT_type = 'rbe2_2d_hole';

                        % Список присоединенных элементов
                        Connected_elements = Connected_ELMs;

                        return;
                        
                    else

                        % Назначение типа присоединенной топологии
                        JT_type = 'plate_rbe2_sequential';
                        
                        % Ранний тест на центрованность присоединенной топологии
                        [Test_Result, Center_Elements] = Plate_RBE2_Seq_Centered_Early_Test(DB_MPC{AT_MPC(MPC_list(1))}.ind_grid, Connected_ELMs);
                        
                        % Список присоединенных элементов (если присоединенная топология центрованная, то учитываются только элементы в окрестности центрального узла)
                        if (Test_Result == 1)
                            Connected_elements = Center_Elements;
                        else
                            Connected_elements = Connected_ELMs;
                        end
                        
                        return;
                        
                    end
                    
                case 3
                    
                    % Должно быть не менее 6 зависимых узлов у RBE2
                    if (size(DB_MPC{AT_MPC(MPC_list(1))}.dep_grid,1) < 6)
                        Err_Message = [sprintf('Сетка, окружающая болт на данном ярусе, потенциально имеет тип RBE2_3D_HOLE\n') ...
                                       sprintf('(см. описание в руководстве пользователя).\n') ...
                                       sprintf('В этом случае у RBE2, к которому крепится болт, должно быть не менее 6 зависимых узлов.\n') ...
                                       sprintf('В данной ситуации число зависимых узлов RBE2, к которому крепится болт, меньше 6.')];
                        return;
                    end
                    
                    % Все присоединенные элементы должны быть типа solid
                    for i=1:size(Connected_ELMs,1)
                        if (~(strcmp(DB_ELEMENTS{AT_ELEMENTS(Connected_ELMs(i))}.type, 'Tet') ...
                           || strcmp(DB_ELEMENTS{AT_ELEMENTS(Connected_ELMs(i))}.type, 'Wedge') ...
                           || strcmp(DB_ELEMENTS{AT_ELEMENTS(Connected_ELMs(i))}.type, 'Hex')))
                            Err_Message = [sprintf('Сетка, окружающая болт на данном ярусе, потенциально имеет тип RBE2_3D_HOLE\n') ...
                                           sprintf('(см. описание в руководстве пользователя).\n') ...
                                           sprintf('В этом случае все конечные элементы, ассоциированные с зависимыми узлами RBE2, к которому крепится болт, должны быть твердотельными.\n') ...
                                           sprintf('В данной ситуации среди элементов, ассоциированных с зависимыми узлами RBE2, существуют элементы другого типа.')];
                            return;
                        end
                    end
                    
                    % Должно быть не меньше 3 элементов
                    if (size(Connected_ELMs,1) < 3)
                        Err_Message = [sprintf('Сетка, окружающая болт на данном ярусе, потенциально имеет тип RBE2_3D_HOLE\n') ...
                                       sprintf('(см. описание в руководстве пользователя).\n') ...
                                       sprintf('В этом случае число конечных элементов, ассоциированных с зависимыми узлами RBE2, к которому крепится болт, должно быть не менее 3.\n') ...
                                       sprintf('В данной ситуации число элементов, ассоциированных с зависимыми узлами RBE2, меньше 3.')];
                        return;
                    end
                    
                    % Все присоединенные элементы должны быть одного порядка
                    switch DB_ELEMENTS{AT_ELEMENTS(Connected_ELMs(1))}.type
                        case 'Tet'
                            switch DB_ELEMENTS{AT_ELEMENTS(Connected_ELMs(1))}.N_nodes
                                case 4
                                    Element_order = 1;
                                case 10
                                    Element_order = 2;
                            end
                        case 'Wedge'
                            switch DB_ELEMENTS{AT_ELEMENTS(Connected_ELMs(1))}.N_nodes
                                case 6
                                    Element_order = 1;
                                case 15
                                    Element_order = 2;
                            end
                        case 'Hex'
                            switch DB_ELEMENTS{AT_ELEMENTS(Connected_ELMs(1))}.N_nodes
                                case 8
                                    Element_order = 1;
                                case 20
                                    Element_order = 2;
                            end
                    end
                    
                    for i=1:size(Connected_ELMs,1)
                        switch DB_ELEMENTS{AT_ELEMENTS(Connected_ELMs(i))}.type
                            case 'Tet'
                                switch Element_order
                                    case 1
                                        if (DB_ELEMENTS{AT_ELEMENTS(Connected_ELMs(i))}.N_nodes ~= 4)
                                            Err_Message = [sprintf('Сетка, окружающая болт на данном ярусе, потенциально имеет тип RBE2_3D_HOLE\n') ...
                                                           sprintf('(см. описание в руководстве пользователя).\n') ...
                                                           sprintf('В этом случае все конечные элементы, ассоциированные с зависимыми узлами RBE2, к которому крепится болт, должны быть одного порядка.\n') ...
                                                           sprintf('В данной ситуации конечные элементы, ассоциированные с зависимыми узлами RBE2, различаются по порядку.')];
                                            return;
                                        end
                                    case 2
                                        if (DB_ELEMENTS{AT_ELEMENTS(Connected_ELMs(i))}.N_nodes ~= 10)
                                            Err_Message = [sprintf('Сетка, окружающая болт на данном ярусе, потенциально имеет тип RBE2_3D_HOLE\n') ...
                                                           sprintf('(см. описание в руководстве пользователя).\n') ...
                                                           sprintf('В этом случае все конечные элементы, ассоциированные с зависимыми узлами RBE2, к которому крепится болт, должны быть одного порядка.\n') ...
                                                           sprintf('В данной ситуации конечные элементы, ассоциированные с зависимыми узлами RBE2, различаются по порядку.')];
                                            return;
                                        end
                                end
                            case 'Wedge'
                                switch Element_order
                                    case 1
                                        if (DB_ELEMENTS{AT_ELEMENTS(Connected_ELMs(i))}.N_nodes ~= 6)
                                            Err_Message = [sprintf('Сетка, окружающая болт на данном ярусе, потенциально имеет тип RBE2_3D_HOLE\n') ...
                                                           sprintf('(см. описание в руководстве пользователя).\n') ...
                                                           sprintf('В этом случае все конечные элементы, ассоциированные с зависимыми узлами RBE2, к которому крепится болт, должны быть одного порядка.\n') ...
                                                           sprintf('В данной ситуации конечные элементы, ассоциированные с зависимыми узлами RBE2, различаются по порядку.')];
                                            return;
                                        end
                                    case 2
                                        if (DB_ELEMENTS{AT_ELEMENTS(Connected_ELMs(i))}.N_nodes ~= 15)
                                            Err_Message = [sprintf('Сетка, окружающая болт на данном ярусе, потенциально имеет тип RBE2_3D_HOLE\n') ...
                                                           sprintf('(см. описание в руководстве пользователя).\n') ...
                                                           sprintf('В этом случае все конечные элементы, ассоциированные с зависимыми узлами RBE2, к которому крепится болт, должны быть одного порядка.\n') ...
                                                           sprintf('В данной ситуации конечные элементы, ассоциированные с зависимыми узлами RBE2, различаются по порядку.')];
                                            return;
                                        end
                                end
                            case 'Hex'
                                switch Element_order
                                    case 1
                                        if (DB_ELEMENTS{AT_ELEMENTS(Connected_ELMs(i))}.N_nodes ~= 8)
                                            Err_Message = [sprintf('Сетка, окружающая болт на данном ярусе, потенциально имеет тип RBE2_3D_HOLE\n') ...
                                                           sprintf('(см. описание в руководстве пользователя).\n') ...
                                                           sprintf('В этом случае все конечные элементы, ассоциированные с зависимыми узлами RBE2, к которому крепится болт, должны быть одного порядка.\n') ...
                                                           sprintf('В данной ситуации конечные элементы, ассоциированные с зависимыми узлами RBE2, различаются по порядку.')];
                                            return;
                                        end
                                    case 2
                                        if (DB_ELEMENTS{AT_ELEMENTS(Connected_ELMs(i))}.N_nodes ~= 20)
                                            Err_Message = [sprintf('Сетка, окружающая болт на данном ярусе, потенциально имеет тип RBE2_3D_HOLE\n') ...
                                                           sprintf('(см. описание в руководстве пользователя).\n') ...
                                                           sprintf('В этом случае все конечные элементы, ассоциированные с зависимыми узлами RBE2, к которому крепится болт, должны быть одного порядка.\n') ...
                                                           sprintf('В данной ситуации конечные элементы, ассоциированные с зависимыми узлами RBE2, различаются по порядку.')];
                                            return;
                                        end
                                end
                        end
                    end
                    
                    % Все присоединенные элементы должны быть совместимы
                    switch DB_ELEMENTS{AT_ELEMENTS(Connected_ELMs(1))}.type
                        case 'Tet'
                            Element_group = 1;
                        case 'Wedge'
                            Element_group = 2;
                        case 'Hex'
                            Element_group = 2;
                    end
                    
                    for i=1:size(Connected_ELMs,1)
                        switch DB_ELEMENTS{AT_ELEMENTS(Connected_ELMs(i))}.type
                            case 'Tet'
                                if (Element_group == 2)
                                    Err_Message = [sprintf('Сетка, окружающая болт на данном ярусе, потенциально имеет тип RBE2_3D_HOLE\n') ...
                                                   sprintf('(см. описание в руководстве пользователя).\n') ...
                                                   sprintf('В этом случае все конечные элементы, ассоциированные с зависимыми узлами RBE2, к которому крепится болт, должны быть совместимы\n') ...
                                                   sprintf('(HEX и WEDGE элементы совместимы между собой, но не совместимы с TET элементами).\n') ...
                                                   sprintf('В данной ситуации среди конечных элементов, ассоциированных с зависимыми узлами RBE2, существуют несовместимые.')];
                                    return;
                                end
                            case 'Wedge'
                                if (Element_group == 1)
                                    Err_Message = [sprintf('Сетка, окружающая болт на данном ярусе, потенциально имеет тип RBE2_3D_HOLE\n') ...
                                                   sprintf('(см. описание в руководстве пользователя).\n') ...
                                                   sprintf('В этом случае все конечные элементы, ассоциированные с зависимыми узлами RBE2, к которому крепится болт, должны быть совместимы\n') ...
                                                   sprintf('(HEX и WEDGE элементы совместимы между собой, но не совместимы с TET элементами).\n') ...
                                                   sprintf('В данной ситуации среди конечных элементов, ассоциированных с зависимыми узлами RBE2, существуют несовместимые.')];
                                    return;
                                end
                            case 'Hex'
                                if (Element_group == 1)
                                    Err_Message = [sprintf('Сетка, окружающая болт на данном ярусе, потенциально имеет тип RBE2_3D_HOLE\n') ...
                                                   sprintf('(см. описание в руководстве пользователя).\n') ...
                                                   sprintf('В этом случае все конечные элементы, ассоциированные с зависимыми узлами RBE2, к которому крепится болт, должны быть совместимы\n') ...
                                                   sprintf('(HEX и WEDGE элементы совместимы между собой, но не совместимы с TET элементами).\n') ...
                                                   sprintf('В данной ситуации среди конечных элементов, ассоциированных с зависимыми узлами RBE2, существуют несовместимые.')];
                                    return;
                                end
                        end
                    end
                    
                    % Назначение типа присоединенной топологии
                    JT_type = 'rbe2_3d_hole';
                    
                    % Список присоединенных элементов
                    Connected_elements = Connected_ELMs;
                    
                    return;
                
            end
            
        case 'RBE3'
            
            % Пока не поддерживается

            Err_Message = [sprintf('Сетка, окружающая болт на данном ярусе, потенциально имеет тип RBE2_2D_HOLE, RBE2_3D_HOLE, либо PLATE_RBE2_SEQUENTIAL\n') ...
                           sprintf('(см. описание в руководстве пользователя).\n') ...
                           sprintf('В этом случае MPC, к которому крепится болт, должен быть типа RBE2.\n') ...
                           sprintf('В данной ситуации MPC имеет отличный от RBE2 тип.')];
            return;
            
    end
    
end

% --- Крепление болта только к элементам ---

if (isempty(MPC_list) && (~isempty(Element_list)))
    
    % Все элементы из списка должны быть либо оболочечные, либо балочные
    All_Shell_flag = 1;
    All_Bar_flag = 1;
    
    for i=1:size(Element_list,1)
        if (~(strcmp(DB_ELEMENTS{AT_ELEMENTS(Element_list(i))}.type, 'Quad') || strcmp(DB_ELEMENTS{AT_ELEMENTS(Element_list(i))}.type, 'Tria')))
            All_Shell_flag = 0;
            break;
        end
    end
    
    for i=1:size(Element_list,1)
        if (~strcmp(DB_ELEMENTS{AT_ELEMENTS(Element_list(i))}.type, 'Bar'))
            All_Bar_flag = 0;
            break;
        end
    end
    
    if ((All_Shell_flag == 0) && (All_Bar_flag == 0))
        Err_Message = [sprintf('Сетка, окружающая болт на данном ярусе, потенциально имеет тип PLATE, BAR_SPIDER_2D_HOLE, либо BAR_SPIDER_3D_HOLE\n') ...
                       sprintf('(см. описание в руководстве пользователя).\n') ...
                       sprintf('В этом случае все конечные элементы, к которым крепится болт, должны быть либо оболочечными, либо балочными.\n') ...
                       sprintf('В данной ситуации среди элементов, к которым крепится болт, существуют элементы другого типа.')];
        return;
    end
    
    % Если все элементы типа shell
    if (All_Shell_flag == 1)
        
        % Должно быть не меньше 3 элементов
        if (size(Element_list,1) < 3)
            Err_Message = [sprintf('Сетка, окружающая болт на данном ярусе, потенциально имеет тип PLATE\n') ...
                           sprintf('(см. описание в руководстве пользователя).\n') ...
                           sprintf('В этом случае число оболочечных элементов, к которым крепится болт, должно быть не менее 3.\n') ...
                           sprintf('В данной ситуации число элементов меньше 3.')];
            return;
        end

        % Все элементы из списка должны быть одного порядка
        switch DB_ELEMENTS{AT_ELEMENTS(Element_list(1))}.type
            case 'Quad'
                switch DB_ELEMENTS{AT_ELEMENTS(Element_list(1))}.N_nodes
                    case 4
                        Element_order = 1;
                    case 8
                        Element_order = 2;
                end
            case 'Tria'
                switch DB_ELEMENTS{AT_ELEMENTS(Element_list(1))}.N_nodes
                    case 3
                        Element_order = 1;
                    case 6
                        Element_order = 2;
                end
        end

        for i=1:size(Element_list,1)
            switch DB_ELEMENTS{AT_ELEMENTS(Element_list(i))}.type
                case 'Quad'
                    switch Element_order
                        case 1
                            if (DB_ELEMENTS{AT_ELEMENTS(Element_list(i))}.N_nodes ~= 4)
                                Err_Message = [sprintf('Сетка, окружающая болт на данном ярусе, потенциально имеет тип PLATE\n') ...
                                               sprintf('(см. описание в руководстве пользователя).\n') ...
                                               sprintf('В этом случае все оболочечные элементы, к которым крепится болт, должны быть одного порядка.\n') ...
                                               sprintf('В данной ситуации элементы различаются по порядку.')];
                                return;
                            end
                        case 2
                            if (DB_ELEMENTS{AT_ELEMENTS(Element_list(i))}.N_nodes ~= 8)
                                Err_Message = [sprintf('Сетка, окружающая болт на данном ярусе, потенциально имеет тип PLATE\n') ...
                                               sprintf('(см. описание в руководстве пользователя).\n') ...
                                               sprintf('В этом случае все оболочечные элементы, к которым крепится болт, должны быть одного порядка.\n') ...
                                               sprintf('В данной ситуации элементы различаются по порядку.')];
                                return;
                            end
                    end
                case 'Tria'
                    switch Element_order
                        case 1
                            if (DB_ELEMENTS{AT_ELEMENTS(Element_list(i))}.N_nodes ~= 3)
                                Err_Message = [sprintf('Сетка, окружающая болт на данном ярусе, потенциально имеет тип PLATE\n') ...
                                               sprintf('(см. описание в руководстве пользователя).\n') ...
                                               sprintf('В этом случае все оболочечные элементы, к которым крепится болт, должны быть одного порядка.\n') ...
                                               sprintf('В данной ситуации элементы различаются по порядку.')];
                                return;
                            end
                        case 2
                            if (DB_ELEMENTS{AT_ELEMENTS(Element_list(i))}.N_nodes ~= 6)
                                Err_Message = [sprintf('Сетка, окружающая болт на данном ярусе, потенциально имеет тип PLATE\n') ...
                                               sprintf('(см. описание в руководстве пользователя).\n') ...
                                               sprintf('В этом случае все оболочечные элементы, к которым крепится болт, должны быть одного порядка.\n') ...
                                               sprintf('В данной ситуации элементы различаются по порядку.')];
                                return;
                            end
                    end
            end
        end

        % Назначение типа присоединенной топологии
        JT_type = 'plate';

        % Список присоединенных элементов
        Connected_elements = Element_list;
        
        return;
        
    end
    
    % Если все элементы балочные
    if (All_Bar_flag == 1)
        
        % Список разветвленных узлов        
        Connected_nodes = Get_Nodes_From_Elements(Element_list, Joint_node);
        
        % Список присоединенных MPC
        Connected_MPCs = Get_MPCs_From_Nodes(Connected_nodes, []);
        
        % Исключение RBE3, служащих для раздачи нагрузки в модели
        if (~isempty(Connected_MPCs))

            Excluded_RBE3 = zeros(10,1);
            counter = 0;

            for i=1:numel(Connected_MPCs)
                if (strcmp(DB_MPC{AT_MPC(Connected_MPCs(i))}.type, 'RBE3'))
                    if (~ismember(DB_MPC{AT_MPC(Connected_MPCs(i))}.dep_grid, Connected_nodes))
                        if (size(DB_MPC{AT_MPC(Connected_MPCs(i))}.ind_data,1) >= Load_RBE3_minimum_indep_nodes)
                            counter = counter + 1;
                            Excluded_RBE3(counter) = Connected_MPCs(i);
                        end
                    end
                end
            end

            if (counter == 0)
                Excluded_RBE3 = [];
            else
                Excluded_RBE3 = Excluded_RBE3(1:counter);
            end

            if (~isempty(Excluded_RBE3))
                Connected_MPCs = setdiff(Connected_MPCs, Excluded_RBE3);
                if (isempty(Connected_MPCs))
                    Connected_MPCs = [];
                end
            end

        end
        
        % Список присоединенных MPC должен быть пустым
        if (~isempty(Connected_MPCs))
            Err_Message = [sprintf('Сетка, окружающая болт на данном ярусе, потенциально имеет тип BAR_SPIDER_2D_HOLE, либо BAR_SPIDER_3D_HOLE\n') ...
                           sprintf('(см. описание в руководстве пользователя).\n') ...
                           sprintf('В этом случае с разветвленными узлами "паука", к которому крепится болт, не должно быть ассоциировано MPC.\n') ...
                           sprintf('(Исключение могут составлять только RBE3, служащие для раздачи нагрузки; у таких RBE3 должно быть не менее %i независимых узлов).\n', Load_RBE3_minimum_indep_nodes) ...
                           sprintf('В данной ситуации существует MPC, ассоциированный с разветвленными узлами "паука".')];
            return;
        end
        
        % Список присоединенных элементов должен быть не пустым
        Connected_ELMs = Get_Elements_From_Nodes(Connected_nodes, Element_list);

        if (isempty(Connected_ELMs))
            Err_Message = [sprintf('Сетка, окружающая болт на данном ярусе, потенциально имеет тип BAR_SPIDER_2D_HOLE, либо BAR_SPIDER_3D_HOLE\n') ...
                           sprintf('(см. описание в руководстве пользователя).\n') ...
                           sprintf('В этом случае с разветвленными узлами "паука" из балок, к которому крепится болт, должны быть ассоциированы конечные элементы.\n') ...
                           sprintf('В данной ситуации с разветвленными узлами "паука" не ассоциировано ни одного элемента.')];
            return;
        end
        
        % У каждого разветвленного узла должны быть присоединенные элементы
        for i=1:size(Connected_nodes,1)
            Single_node_elements = Get_Elements_From_Nodes(Connected_nodes(i), Element_list);
            if (isempty(Single_node_elements))
                Err_Message = [sprintf('Сетка, окружающая болт на данном ярусе, потенциально имеет тип BAR_SPIDER_2D_HOLE, либо BAR_SPIDER_3D_HOLE\n') ...
                               sprintf('(см. описание в руководстве пользователя).\n') ...
                               sprintf('В этом случае с каждым разветвленным узлом "паука" из балок, к которому крепится болт, должен быть ассоциирован хотя бы один конечный элемент.\n') ...
                               sprintf('В данной ситуации существует разветвленный узел "паука", с которым не ассоциировано ни одного элемента.')];
                return;
            end
        end
        
        % Первый присоединенный элемент должен быть shell, либо solid
        switch DB_ELEMENTS{AT_ELEMENTS(Connected_ELMs(1))}.type
            case 'Tet'
                % Допустимый тип элемента
                Elm_family = 3;
            case 'Wedge'
                % Допустимый тип элемента
                Elm_family = 3;
            case 'Hex'
                % Допустимый тип элемента
                Elm_family = 3;
            case 'Quad'
                % Допустимый тип элемента
                Elm_family = 2;
            case 'Tria'
                % Допустимый тип элемента
                Elm_family = 2;
            otherwise
                Err_Message = [sprintf('Сетка, окружающая болт на данном ярусе, потенциально имеет тип BAR_SPIDER_2D_HOLE, либо BAR_SPIDER_3D_HOLE\n') ...
                               sprintf('(см. описание в руководстве пользователя).\n') ...
                               sprintf('В этом случае с разветвленными узлами "паука" из балок, к которому крепится болт, должны быть ассоциированы оболочечные, либо твердотельные конечные элементы.\n') ...
                               sprintf('В данной ситуации существует разветвленный узел "паука", с которым ассоциированы элементы другого типа.')];
                return;
        end
        
        % Ветвление по семейству элементов
        switch Elm_family

            case 2
                
                % Должно быть не менее 3 балочных элементов
                if (size(Element_list,1) < 3)
                    Err_Message = [sprintf('Сетка, окружающая болт на данном ярусе, потенциально имеет тип BAR_SPIDER_2D_HOLE\n') ...
                                   sprintf('(см. описание в руководстве пользователя).\n') ...
                                   sprintf('В этом случае у "паука" из балок, к которому крепится болт, должно быть не менее 3 лучей.\n') ...
                                   sprintf('В данной ситуации число лучей у "паука" из балок, к которому крепится болт, меньше 3.')];
                    return;
                end

                % Все присоединенные элементы должны быть типа shell
                for i=1:size(Connected_ELMs,1)
                    if (~(strcmp(DB_ELEMENTS{AT_ELEMENTS(Connected_ELMs(i))}.type, 'Quad') ...
                       || strcmp(DB_ELEMENTS{AT_ELEMENTS(Connected_ELMs(i))}.type, 'Tria')))
                        Err_Message = [sprintf('Сетка, окружающая болт на данном ярусе, потенциально имеет тип BAR_SPIDER_2D_HOLE\n') ...
                                       sprintf('(см. описание в руководстве пользователя).\n') ...
                                       sprintf('В этом случае все конечные элементы, ассоциированные с разветвленными узлами "паука" из балок, к которому крепится болт, должны быть оболочечными.\n') ...
                                       sprintf('В данной ситуации среди элементов, ассоциированных с разветвленными узлами "паука", существуют элементы другого типа.')];
                        return;
                    end
                end

                % Должно быть не меньше 3 элементов
                if (size(Connected_ELMs,1) < 3)
                    Err_Message = [sprintf('Сетка, окружающая болт на данном ярусе, потенциально имеет тип BAR_SPIDER_2D_HOLE\n') ...
                                   sprintf('(см. описание в руководстве пользователя).\n') ...
                                   sprintf('В этом случае число конечных элементов, ассоциированных с разветвленными узлами "паука" из балок, к которому крепится болт, должно быть не менее 3.\n') ...
                                   sprintf('В данной ситуации число элементов, ассоциированных с разветвленными узлами "паука", меньше 3.')];
                    return;
                end

                % Все присоединенные элементы должны быть одного порядка
                switch DB_ELEMENTS{AT_ELEMENTS(Connected_ELMs(1))}.type
                    case 'Quad'
                        switch DB_ELEMENTS{AT_ELEMENTS(Connected_ELMs(1))}.N_nodes
                            case 4
                                Element_order = 1;
                            case 8
                                Element_order = 2;
                        end
                    case 'Tria'
                        switch DB_ELEMENTS{AT_ELEMENTS(Connected_ELMs(1))}.N_nodes
                            case 3
                                Element_order = 1;
                            case 6
                                Element_order = 2;
                        end
                end

                for i=1:size(Connected_ELMs,1)
                    switch DB_ELEMENTS{AT_ELEMENTS(Connected_ELMs(i))}.type
                        case 'Quad'
                            switch Element_order
                                case 1
                                    if (DB_ELEMENTS{AT_ELEMENTS(Connected_ELMs(i))}.N_nodes ~= 4)
                                        Err_Message = [sprintf('Сетка, окружающая болт на данном ярусе, потенциально имеет тип BAR_SPIDER_2D_HOLE\n') ...
                                                       sprintf('(см. описание в руководстве пользователя).\n') ...
                                                       sprintf('В этом случае все конечные элементы, ассоциированные с разветвленными узлами "паука" из балок, к которому крепится болт, должны быть одного порядка.\n') ...
                                                       sprintf('В данной ситуации конечные элементы, ассоциированные с разветвленными узлами "паука", различаются по порядку.')];
                                        return;
                                    end
                                case 2
                                    if (DB_ELEMENTS{AT_ELEMENTS(Connected_ELMs(i))}.N_nodes ~= 8)
                                        Err_Message = [sprintf('Сетка, окружающая болт на данном ярусе, потенциально имеет тип BAR_SPIDER_2D_HOLE\n') ...
                                                       sprintf('(см. описание в руководстве пользователя).\n') ...
                                                       sprintf('В этом случае все конечные элементы, ассоциированные с разветвленными узлами "паука" из балок, к которому крепится болт, должны быть одного порядка.\n') ...
                                                       sprintf('В данной ситуации конечные элементы, ассоциированные с разветвленными узлами "паука", различаются по порядку.')];
                                        return;
                                    end
                            end
                        case 'Tria'
                            switch Element_order
                                case 1
                                    if (DB_ELEMENTS{AT_ELEMENTS(Connected_ELMs(i))}.N_nodes ~= 3)
                                        Err_Message = [sprintf('Сетка, окружающая болт на данном ярусе, потенциально имеет тип BAR_SPIDER_2D_HOLE\n') ...
                                                       sprintf('(см. описание в руководстве пользователя).\n') ...
                                                       sprintf('В этом случае все конечные элементы, ассоциированные с разветвленными узлами "паука" из балок, к которому крепится болт, должны быть одного порядка.\n') ...
                                                       sprintf('В данной ситуации конечные элементы, ассоциированные с разветвленными узлами "паука", различаются по порядку.')];
                                        return;
                                    end
                                case 2
                                    if (DB_ELEMENTS{AT_ELEMENTS(Connected_ELMs(i))}.N_nodes ~= 6)
                                        Err_Message = [sprintf('Сетка, окружающая болт на данном ярусе, потенциально имеет тип BAR_SPIDER_2D_HOLE\n') ...
                                                       sprintf('(см. описание в руководстве пользователя).\n') ...
                                                       sprintf('В этом случае все конечные элементы, ассоциированные с разветвленными узлами "паука" из балок, к которому крепится болт, должны быть одного порядка.\n') ...
                                                       sprintf('В данной ситуации конечные элементы, ассоциированные с разветвленными узлами "паука", различаются по порядку.')];
                                        return;
                                    end
                            end
                    end
                end
                
                % Тест на 2d отверстие
                if (Hole_2D_Test(Joint_node, Connected_nodes, Element_list))
                    
                    % Назначение типа присоединенной топологии
                    JT_type = 'bar_spider_2d_hole';

                    % Список присоединенных элементов
                    Connected_elements = Connected_ELMs;

                    % Список элементов в пауке
                    Bar_Spider_Elements = Element_list;

                    % Список разветвленных узлов в пауке
                    Bar_Spider_Connected_Nodes = Connected_nodes;

                    return;
                    
                else
                    
                    Err_Message = [sprintf('Сетка, окружающая болт на данном ярусе, потенциально имеет тип BAR_SPIDER_2D_HOLE\n') ...
                                   sprintf('(см. описание в руководстве пользователя).\n') ...
                                   sprintf('В этом случае "паук" из балок, к которому крепится болт, должен быть присоединен к 2D отверстию в сетке.\n') ...
                                   sprintf('В данной ситуации тест на 2D отверстие не был пройден.')];
                    
                    return;
                    
                end

            case 3
                
                % Должно быть не менее 6 балочных элементов
                if (size(Element_list,1) < 6)
                    Err_Message = [sprintf('Сетка, окружающая болт на данном ярусе, потенциально имеет тип BAR_SPIDER_3D_HOLE\n') ...
                                   sprintf('(см. описание в руководстве пользователя).\n') ...
                                   sprintf('В этом случае у "паука" из балок, к которому крепится болт, должно быть не менее 6 лучей.\n') ...
                                   sprintf('В данной ситуации число лучей у "паука" из балок, к которому крепится болт, меньше 6.')];
                    return;
                end

                % Все присоединенные элементы должны быть типа solid
                for i=1:size(Connected_ELMs,1)
                    if (~(strcmp(DB_ELEMENTS{AT_ELEMENTS(Connected_ELMs(i))}.type, 'Tet') ...
                       || strcmp(DB_ELEMENTS{AT_ELEMENTS(Connected_ELMs(i))}.type, 'Wedge') ...
                       || strcmp(DB_ELEMENTS{AT_ELEMENTS(Connected_ELMs(i))}.type, 'Hex')))
                        Err_Message = [sprintf('Сетка, окружающая болт на данном ярусе, потенциально имеет тип BAR_SPIDER_3D_HOLE\n') ...
                                       sprintf('(см. описание в руководстве пользователя).\n') ...
                                       sprintf('В этом случае все конечные элементы, ассоциированные с "пауком" из балок, к которому крепится болт, должны быть твердотельными.\n') ...
                                       sprintf('В данной ситуации среди элементов, ассоциированных с "пауком" из балок, существуют элементы другого типа.')];
                        return;
                    end
                end

                % Должно быть не меньше 3 элементов
                if (size(Connected_ELMs,1) < 3)
                    Err_Message = [sprintf('Сетка, окружающая болт на данном ярусе, потенциально имеет тип BAR_SPIDER_3D_HOLE\n') ...
                                   sprintf('(см. описание в руководстве пользователя).\n') ...
                                   sprintf('В этом случае число конечных элементов, ассоциированных с "пауком" из балок, к которому крепится болт, должно быть не менее 3.\n') ...
                                   sprintf('В данной ситуации число элементов, ассоциированных с "пауком" из балок, меньше 3.')];
                    return;
                end

                % Все присоединенные элементы должны быть одного порядка
                switch DB_ELEMENTS{AT_ELEMENTS(Connected_ELMs(1))}.type
                    case 'Tet'
                        switch DB_ELEMENTS{AT_ELEMENTS(Connected_ELMs(1))}.N_nodes
                            case 4
                                Element_order = 1;
                            case 10
                                Element_order = 2;
                        end
                    case 'Wedge'
                        switch DB_ELEMENTS{AT_ELEMENTS(Connected_ELMs(1))}.N_nodes
                            case 6
                                Element_order = 1;
                            case 15
                                Element_order = 2;
                        end
                    case 'Hex'
                        switch DB_ELEMENTS{AT_ELEMENTS(Connected_ELMs(1))}.N_nodes
                            case 8
                                Element_order = 1;
                            case 20
                                Element_order = 2;
                        end
                end

                for i=1:size(Connected_ELMs,1)
                    switch DB_ELEMENTS{AT_ELEMENTS(Connected_ELMs(i))}.type
                        case 'Tet'
                            switch Element_order
                                case 1
                                    if (DB_ELEMENTS{AT_ELEMENTS(Connected_ELMs(i))}.N_nodes ~= 4)
                                        Err_Message = [sprintf('Сетка, окружающая болт на данном ярусе, потенциально имеет тип BAR_SPIDER_3D_HOLE\n') ...
                                                       sprintf('(см. описание в руководстве пользователя).\n') ...
                                                       sprintf('В этом случае все конечные элементы, ассоциированные с "пауком" из балок, к которому крепится болт, должны быть одного порядка.\n') ...
                                                       sprintf('В данной ситуации конечные элементы, ассоциированные с "пауком" из балок, различаются по порядку.')];
                                        return;
                                    end
                                case 2
                                    if (DB_ELEMENTS{AT_ELEMENTS(Connected_ELMs(i))}.N_nodes ~= 10)
                                        Err_Message = [sprintf('Сетка, окружающая болт на данном ярусе, потенциально имеет тип BAR_SPIDER_3D_HOLE\n') ...
                                                       sprintf('(см. описание в руководстве пользователя).\n') ...
                                                       sprintf('В этом случае все конечные элементы, ассоциированные с "пауком" из балок, к которому крепится болт, должны быть одного порядка.\n') ...
                                                       sprintf('В данной ситуации конечные элементы, ассоциированные с "пауком" из балок, различаются по порядку.')];
                                        return;
                                    end
                            end
                        case 'Wedge'
                            switch Element_order
                                case 1
                                    if (DB_ELEMENTS{AT_ELEMENTS(Connected_ELMs(i))}.N_nodes ~= 6)
                                        Err_Message = [sprintf('Сетка, окружающая болт на данном ярусе, потенциально имеет тип BAR_SPIDER_3D_HOLE\n') ...
                                                       sprintf('(см. описание в руководстве пользователя).\n') ...
                                                       sprintf('В этом случае все конечные элементы, ассоциированные с "пауком" из балок, к которому крепится болт, должны быть одного порядка.\n') ...
                                                       sprintf('В данной ситуации конечные элементы, ассоциированные с "пауком" из балок, различаются по порядку.')];
                                        return;
                                    end
                                case 2
                                    if (DB_ELEMENTS{AT_ELEMENTS(Connected_ELMs(i))}.N_nodes ~= 15)
                                        Err_Message = [sprintf('Сетка, окружающая болт на данном ярусе, потенциально имеет тип BAR_SPIDER_3D_HOLE\n') ...
                                                       sprintf('(см. описание в руководстве пользователя).\n') ...
                                                       sprintf('В этом случае все конечные элементы, ассоциированные с "пауком" из балок, к которому крепится болт, должны быть одного порядка.\n') ...
                                                       sprintf('В данной ситуации конечные элементы, ассоциированные с "пауком" из балок, различаются по порядку.')];
                                        return;
                                    end
                            end
                        case 'Hex'
                            switch Element_order
                                case 1
                                    if (DB_ELEMENTS{AT_ELEMENTS(Connected_ELMs(i))}.N_nodes ~= 8)
                                        Err_Message = [sprintf('Сетка, окружающая болт на данном ярусе, потенциально имеет тип BAR_SPIDER_3D_HOLE\n') ...
                                                       sprintf('(см. описание в руководстве пользователя).\n') ...
                                                       sprintf('В этом случае все конечные элементы, ассоциированные с "пауком" из балок, к которому крепится болт, должны быть одного порядка.\n') ...
                                                       sprintf('В данной ситуации конечные элементы, ассоциированные с "пауком" из балок, различаются по порядку.')];
                                        return;
                                    end
                                case 2
                                    if (DB_ELEMENTS{AT_ELEMENTS(Connected_ELMs(i))}.N_nodes ~= 20)
                                        Err_Message = [sprintf('Сетка, окружающая болт на данном ярусе, потенциально имеет тип BAR_SPIDER_3D_HOLE\n') ...
                                                       sprintf('(см. описание в руководстве пользователя).\n') ...
                                                       sprintf('В этом случае все конечные элементы, ассоциированные с "пауком" из балок, к которому крепится болт, должны быть одного порядка.\n') ...
                                                       sprintf('В данной ситуации конечные элементы, ассоциированные с "пауком" из балок, различаются по порядку.')];
                                        return;
                                    end
                            end
                    end
                end

                % Все присоединенные элементы должны быть совместимы
                switch DB_ELEMENTS{AT_ELEMENTS(Connected_ELMs(1))}.type
                    case 'Tet'
                        Element_group = 1;
                    case 'Wedge'
                        Element_group = 2;
                    case 'Hex'
                        Element_group = 2;
                end

                for i=1:size(Connected_ELMs,1)
                    switch DB_ELEMENTS{AT_ELEMENTS(Connected_ELMs(i))}.type
                        case 'Tet'
                            if (Element_group == 2)
                                Err_Message = [sprintf('Сетка, окружающая болт на данном ярусе, потенциально имеет тип BAR_SPIDER_3D_HOLE\n') ...
                                               sprintf('(см. описание в руководстве пользователя).\n') ...
                                               sprintf('В этом случае все конечные элементы, ассоциированные с "пауком" из балок, к которому крепится болт, должны быть совместимы\n') ...
                                               sprintf('(HEX и WEDGE элементы совместимы между собой, но не совместимы с TET элементами).\n') ...
                                               sprintf('В данной ситуации среди конечных элементов, ассоциированных с "пауком" из балок, существуют несовместимые.')];
                                return;
                            end
                        case 'Wedge'
                            if (Element_group == 1)
                                Err_Message = [sprintf('Сетка, окружающая болт на данном ярусе, потенциально имеет тип BAR_SPIDER_3D_HOLE\n') ...
                                               sprintf('(см. описание в руководстве пользователя).\n') ...
                                               sprintf('В этом случае все конечные элементы, ассоциированные с "пауком" из балок, к которому крепится болт, должны быть совместимы\n') ...
                                               sprintf('(HEX и WEDGE элементы совместимы между собой, но не совместимы с TET элементами).\n') ...
                                               sprintf('В данной ситуации среди конечных элементов, ассоциированных с "пауком" из балок, существуют несовместимые.')];
                                return;
                            end
                        case 'Hex'
                            if (Element_group == 1)
                                Err_Message = [sprintf('Сетка, окружающая болт на данном ярусе, потенциально имеет тип BAR_SPIDER_3D_HOLE\n') ...
                                               sprintf('(см. описание в руководстве пользователя).\n') ...
                                               sprintf('В этом случае все конечные элементы, ассоциированные с "пауком" из балок, к которому крепится болт, должны быть совместимы\n') ...
                                               sprintf('(HEX и WEDGE элементы совместимы между собой, но не совместимы с TET элементами).\n') ...
                                               sprintf('В данной ситуации среди конечных элементов, ассоциированных с "пауком" из балок, существуют несовместимые.')];
                                return;
                            end
                    end
                end

                % Назначение типа присоединенной топологии
                JT_type = 'bar_spider_3d_hole';

                % Список присоединенных элементов
                Connected_elements = Connected_ELMs;
                
                % Список элементов в пауке
                Bar_Spider_Elements = Element_list;
                
                % Список разветвленных узлов в пауке
                Bar_Spider_Connected_Nodes = Connected_nodes;
                
                return;

        end
        
    end
    
end

% --- Крепление болта и к MPC, и к элементам ---

if ((~isempty(MPC_list)) && (~isempty(Element_list)))
    
    % Все элементы из списка должны быть типа shell
    for i=1:size(Element_list,1)
        if (~(strcmp(DB_ELEMENTS{AT_ELEMENTS(Element_list(i))}.type, 'Quad') || strcmp(DB_ELEMENTS{AT_ELEMENTS(Element_list(i))}.type, 'Tria')))
            Err_Message = [sprintf('Сетка, окружающая болт на данном ярусе, потенциально имеет тип PLATE_RBE2_PARALLEL\n') ...
                           sprintf('(см. описание в руководстве пользователя).\n') ...
                           sprintf('В этом случае все конечные элементы, к которым крепится болт, должны быть оболочечными.\n') ...
                           sprintf('В данной ситуации среди элементов, к которым крепится болт, существуют элементы другого типа.')];
            return;
        end
    end
    
    % Должно быть не меньше 3 элементов
    if (size(Element_list,1) < 3)
        Err_Message = [sprintf('Сетка, окружающая болт на данном ярусе, потенциально имеет тип PLATE_RBE2_PARALLEL\n') ...
                       sprintf('(см. описание в руководстве пользователя).\n') ...
                       sprintf('В этом случае число оболочечных элементов, к которым крепится болт, должно быть не менее 3.\n') ...
                       sprintf('В данной ситуации число элементов меньше 3.')];
        return;
    end
    
    % Все элементы из списка должны быть одного порядка
    switch DB_ELEMENTS{AT_ELEMENTS(Element_list(1))}.type
        case 'Quad'
            switch DB_ELEMENTS{AT_ELEMENTS(Element_list(1))}.N_nodes
                case 4
                    Element_order = 1;
                case 8
                    Element_order = 2;
            end
        case 'Tria'
            switch DB_ELEMENTS{AT_ELEMENTS(Element_list(1))}.N_nodes
                case 3
                    Element_order = 1;
                case 6
                    Element_order = 2;
            end
    end

    for i=1:size(Element_list,1)
        switch DB_ELEMENTS{AT_ELEMENTS(Element_list(i))}.type
            case 'Quad'
                switch Element_order
                    case 1
                        if (DB_ELEMENTS{AT_ELEMENTS(Element_list(i))}.N_nodes ~= 4)
                            Err_Message = [sprintf('Сетка, окружающая болт на данном ярусе, потенциально имеет тип PLATE_RBE2_PARALLEL\n') ...
                                           sprintf('(см. описание в руководстве пользователя).\n') ...
                                           sprintf('В этом случае все оболочечные элементы, к которым крепится болт, должны быть одного порядка.\n') ...
                                           sprintf('В данной ситуации элементы различаются по порядку.')];
                            return;
                        end
                    case 2
                        if (DB_ELEMENTS{AT_ELEMENTS(Element_list(i))}.N_nodes ~= 8)
                            Err_Message = [sprintf('Сетка, окружающая болт на данном ярусе, потенциально имеет тип PLATE_RBE2_PARALLEL\n') ...
                                           sprintf('(см. описание в руководстве пользователя).\n') ...
                                           sprintf('В этом случае все оболочечные элементы, к которым крепится болт, должны быть одного порядка.\n') ...
                                           sprintf('В данной ситуации элементы различаются по порядку.')];
                            return;
                        end
                end
            case 'Tria'
                switch Element_order
                    case 1
                        if (DB_ELEMENTS{AT_ELEMENTS(Element_list(i))}.N_nodes ~= 3)
                            Err_Message = [sprintf('Сетка, окружающая болт на данном ярусе, потенциально имеет тип PLATE_RBE2_PARALLEL\n') ...
                                           sprintf('(см. описание в руководстве пользователя).\n') ...
                                           sprintf('В этом случае все оболочечные элементы, к которым крепится болт, должны быть одного порядка.\n') ...
                                           sprintf('В данной ситуации элементы различаются по порядку.')];
                            return;
                        end
                    case 2
                        if (DB_ELEMENTS{AT_ELEMENTS(Element_list(i))}.N_nodes ~= 6)
                            Err_Message = [sprintf('Сетка, окружающая болт на данном ярусе, потенциально имеет тип PLATE_RBE2_PARALLEL\n') ...
                                           sprintf('(см. описание в руководстве пользователя).\n') ...
                                           sprintf('В этом случае все оболочечные элементы, к которым крепится болт, должны быть одного порядка.\n') ...
                                           sprintf('В данной ситуации элементы различаются по порядку.')];
                            return;
                        end
                end
        end
    end
    
    % Должен быть один MPC
    if (size(MPC_list,1) ~= 1)
        Err_Message = [sprintf('Сетка, окружающая болт на данном ярусе, потенциально имеет тип PLATE_RBE2_PARALLEL\n') ...
                       sprintf('(см. описание в руководстве пользователя).\n') ...
                       sprintf('В этом случае болт должен соединяться лишь с одним MPC.\n') ...
                       sprintf('В данной ситуации болт соединен с несколькими MPC.')];
        return;
    end
    
    % Допускается тип MPC RBE2 или RBE3
    if (~(strcmp(DB_MPC{AT_MPC(MPC_list(1))}.type, 'RBE2') || strcmp(DB_MPC{AT_MPC(MPC_list(1))}.type, 'RBE3')))
        Err_Message = [sprintf('Сетка, окружающая болт на данном ярусе, потенциально имеет тип PLATE_RBE2_PARALLEL\n') ...
                       sprintf('(см. описание в руководстве пользователя).\n') ...
                       sprintf('В этом случае MPC, к которому крепится болт, должен быть типа RBE2.\n') ...
                       sprintf('В данной ситуации MPC имеет отличный от RBE2 тип.')];
        return;
    end
    
    % Ветвление по типу MPC
    switch DB_MPC{AT_MPC(MPC_list(1))}.type
    
        case 'RBE2'
            
            % Узел Joint_node должен быть независимым
            if (DB_MPC{AT_MPC(MPC_list(1))}.ind_grid ~= Joint_node)
                Err_Message = [sprintf('Сетка, окружающая болт на данном ярусе, потенциально имеет тип PLATE_RBE2_PARALLEL\n') ...
                               sprintf('(см. описание в руководстве пользователя).\n') ...
                               sprintf('В этом случае узел MPC, к которому крепится болт, должен быть независимым.\n') ...
                               sprintf('В данной ситуации болт крепится к зависимому узлу MPC.')];
                return;
            end
            
            % Список присоединенных MPC у зависимых узлов
            Connected_MPCs = Get_MPCs_From_Nodes(DB_MPC{AT_MPC(MPC_list(1))}.dep_grid, MPC_list(1));
            
            % Исключение RBE3, служащих для раздачи нагрузки в модели
            if (~isempty(Connected_MPCs))
            
                Excluded_RBE3 = zeros(10,1);
                counter = 0;

                for i=1:numel(Connected_MPCs)
                    if (strcmp(DB_MPC{AT_MPC(Connected_MPCs(i))}.type, 'RBE3'))
                        if (~ismember(DB_MPC{AT_MPC(Connected_MPCs(i))}.dep_grid, DB_MPC{AT_MPC(MPC_list(1))}.dep_grid))
                            if (size(DB_MPC{AT_MPC(Connected_MPCs(i))}.ind_data,1) >= Load_RBE3_minimum_indep_nodes)
                                counter = counter + 1;
                                Excluded_RBE3(counter) = Connected_MPCs(i);
                            end
                        end
                    end
                end
                
                if (counter == 0)
                    Excluded_RBE3 = [];
                else
                    Excluded_RBE3 = Excluded_RBE3(1:counter);
                end
                
                if (~isempty(Excluded_RBE3))
                    Connected_MPCs = setdiff(Connected_MPCs, Excluded_RBE3);
                    if (isempty(Connected_MPCs))
                        Connected_MPCs = [];
                    end
                end
            
            end
            
            % Список присоединенных MPC у зависимых узлов должен быть пустым
            if (~isempty(Connected_MPCs))
                Err_Message = [sprintf('Сетка, окружающая болт на данном ярусе, потенциально имеет тип PLATE_RBE2_PARALLEL\n') ...
                               sprintf('(см. описание в руководстве пользователя).\n') ...
                               sprintf('В этом случае с зависимыми узлами RBE2, к которому крепится болт, не должно быть ассоциировано никаких иных MPC.\n') ...
                               sprintf('(Исключение могут составлять только RBE3, служащие для раздачи нагрузки; у таких RBE3 должно быть не менее %i независимых узлов).\n', Load_RBE3_minimum_indep_nodes) ...
                               sprintf('В данной ситуации существует посторонний MPC, ассоциированный с зависимыми узлами RBE2.')];
                return;
            end
            
            % Список присоединенных элементов у зависимых узлов должен быть не пустым
            Connected_ELMs = Get_Elements_From_Nodes(DB_MPC{AT_MPC(MPC_list(1))}.dep_grid, []);
            
            if (isempty(Connected_ELMs))
                Err_Message = [sprintf('Сетка, окружающая болт на данном ярусе, потенциально имеет тип PLATE_RBE2_PARALLEL\n') ...
                               sprintf('(см. описание в руководстве пользователя).\n') ...
                               sprintf('В этом случае с зависимыми узлами RBE2, к которому крепится болт, должны быть ассоциированы конечные элементы.\n') ...
                               sprintf('В данной ситуации с зависимыми узлами RBE2 не ассоциировано ни одного элемента.')];
                return;
            end
            
            % У каждого зависимого узла MPC должны быть присоединенные элементы
            for i=1:size(DB_MPC{AT_MPC(MPC_list(1))}.dep_grid,1)
                Single_node_elements = Get_Elements_From_Nodes(DB_MPC{AT_MPC(MPC_list(1))}.dep_grid(i), []);
                if (isempty(Single_node_elements))
                    Err_Message = [sprintf('Сетка, окружающая болт на данном ярусе, потенциально имеет тип PLATE_RBE2_PARALLEL\n') ...
                                   sprintf('(см. описание в руководстве пользователя).\n') ...
                                   sprintf('В этом случае с каждым зависимым узлом RBE2, к которому крепится болт, должен быть ассоциирован хотя бы один конечный элемент.\n') ...
                                   sprintf('В данной ситуации существует зависимый узел RBE2, с которым не ассоциировано ни одного элемента.')];
                    return;
                end
            end
            
            % Все присоединенные к зависимым узлам RBE2 элементы должны быть типа shell
            for i=1:size(Connected_ELMs,1)
                if (~(strcmp(DB_ELEMENTS{AT_ELEMENTS(Connected_ELMs(i))}.type, 'Quad') ...
                   || strcmp(DB_ELEMENTS{AT_ELEMENTS(Connected_ELMs(i))}.type, 'Tria')))
                    Err_Message = [sprintf('Сетка, окружающая болт на данном ярусе, потенциально имеет тип PLATE_RBE2_PARALLEL\n') ...
                                   sprintf('(см. описание в руководстве пользователя).\n') ...
                                   sprintf('В этом случае с зависимыми узлами RBE2, к которому крепится болт, должны быть ассоциированы оболочечные элементы.\n') ...
                                   sprintf('В данной ситуации существует зависимый узел RBE2, с которым ассоциированы элементы другого типа.')];
                    return;
                end
            end
            
            % Все присоединенные к зависимым узлам RBE2 элементы должны быть того же порядка, что и центральные элементы
            for i=1:size(Connected_ELMs,1)
                switch DB_ELEMENTS{AT_ELEMENTS(Connected_ELMs(i))}.type
                    case 'Quad'
                        switch Element_order
                            case 1
                                if (DB_ELEMENTS{AT_ELEMENTS(Connected_ELMs(i))}.N_nodes ~= 4)
                                    Err_Message = [sprintf('Сетка, окружающая болт на данном ярусе, потенциально имеет тип PLATE_RBE2_PARALLEL\n') ...
                                                   sprintf('(см. описание в руководстве пользователя).\n') ...
                                                   sprintf('В этом случае все конечные элементы, ассоциированные с зависимыми узлами RBE2, к которому крепится болт,\n') ...
                                                   sprintf('должны быть того же порядка, что и оболочечные элементы, непосредственно окружающие болт.\n') ...
                                                   sprintf('В данной ситуации среди всех упомянутых выше элементов существуют элементы разного порядка.')];
                                    return;
                                end
                            case 2
                                if (DB_ELEMENTS{AT_ELEMENTS(Connected_ELMs(i))}.N_nodes ~= 8)
                                    Err_Message = [sprintf('Сетка, окружающая болт на данном ярусе, потенциально имеет тип PLATE_RBE2_PARALLEL\n') ...
                                                   sprintf('(см. описание в руководстве пользователя).\n') ...
                                                   sprintf('В этом случае все конечные элементы, ассоциированные с зависимыми узлами RBE2, к которому крепится болт,\n') ...
                                                   sprintf('должны быть того же порядка, что и оболочечные элементы, непосредственно окружающие болт.\n') ...
                                                   sprintf('В данной ситуации среди всех упомянутых выше элементов существуют элементы разного порядка.')];
                                    return;
                                end
                        end
                    case 'Tria'
                        switch Element_order
                            case 1
                                if (DB_ELEMENTS{AT_ELEMENTS(Connected_ELMs(i))}.N_nodes ~= 3)
                                    Err_Message = [sprintf('Сетка, окружающая болт на данном ярусе, потенциально имеет тип PLATE_RBE2_PARALLEL\n') ...
                                                   sprintf('(см. описание в руководстве пользователя).\n') ...
                                                   sprintf('В этом случае все конечные элементы, ассоциированные с зависимыми узлами RBE2, к которому крепится болт,\n') ...
                                                   sprintf('должны быть того же порядка, что и оболочечные элементы, непосредственно окружающие болт.\n') ...
                                                   sprintf('В данной ситуации среди всех упомянутых выше элементов существуют элементы разного порядка.')];
                                    return;
                                end
                            case 2
                                if (DB_ELEMENTS{AT_ELEMENTS(Connected_ELMs(i))}.N_nodes ~= 6)
                                    Err_Message = [sprintf('Сетка, окружающая болт на данном ярусе, потенциально имеет тип PLATE_RBE2_PARALLEL\n') ...
                                                   sprintf('(см. описание в руководстве пользователя).\n') ...
                                                   sprintf('В этом случае все конечные элементы, ассоциированные с зависимыми узлами RBE2, к которому крепится болт,\n') ...
                                                   sprintf('должны быть того же порядка, что и оболочечные элементы, непосредственно окружающие болт.\n') ...
                                                   sprintf('В данной ситуации среди всех упомянутых выше элементов существуют элементы разного порядка.')];
                                    return;
                                end
                        end
                end
            end
            
            % Должно быть не менее 2 зависимых узлов у RBE2
            if (size(DB_MPC{AT_MPC(MPC_list(1))}.dep_grid,1) < 2)
                Err_Message = [sprintf('Сетка, окружающая болт на данном ярусе, потенциально имеет тип PLATE_RBE2_PARALLEL\n') ...
                               sprintf('(см. описание в руководстве пользователя).\n') ...
                               sprintf('В этом случае у RBE2, к которому крепится болт, должно быть не менее 2 зависимых узлов.\n') ...
                               sprintf('В данной ситуации число зависимых узлов RBE2, к которому крепится болт, меньше 2.')];
                return;
            end
            
            % Назначение типа присоединенной топологии
            JT_type = 'plate_rbe2_parallel';

            % Список присоединенных элементов (учитываются только элементы, присоединенные к независимому узлу)
            Connected_elements = Element_list;

            return;
            
        case 'RBE3'
            
            % Пока не поддерживается
            
            Err_Message = [sprintf('Сетка, окружающая болт на данном ярусе, потенциально имеет тип PLATE_RBE2_PARALLEL\n') ...
                           sprintf('(см. описание в руководстве пользователя).\n') ...
                           sprintf('В этом случае MPC, к которому крепится болт, должен быть типа RBE2.\n') ...
                           sprintf('В данной ситуации MPC имеет отличный от RBE2 тип.')];
            
            return;
            
    end

end

% --- Болт ни к чему не прикреплен ---

if (isempty(MPC_list) && isempty(Element_list))
    
    Err_Message = [sprintf('На данном ярусе отсутствуют элементы или MPC, окружающие болт.\n') ...
                   sprintf('Вместе с каждым болтом на каждом соединяемом ярусе в bdf файле должен быть иметься кусок сетки, окружающий болт со всех сторон.\n') ...
                   sprintf('Требуется хотя бы один ряд конечных элементов вокруг болта.')];
    
    return;
end
